package com.zk.client.impl;

import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import com.zk.client.ZkConfig;
import com.zk.client.ZkConfigBuilder;
import com.zk.client.ZkConfigConstant;
import com.zk.ZkClientHelper;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.utils.CloseableUtils;
import org.apache.curator.utils.ZKPaths;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;

/**
 * 持有PathChildrenCache对象, 初始化App Name和Group组,构建路径,
 * 
 * @author haitao.wang
 * 
 */
public class ZkConfigImpl implements ZkConfig {
	private final Logger log = LoggerFactory.getLogger(this.getClass());

	private PathChildrenCache cache = null;
	private String nodeFullPath;
	private ZkConfigBuilder builder;

	/**
	 * 构造函数，从Builder中获取参数构建
	 * 
	 */
	public ZkConfigImpl(ZkConfigBuilder thisBuilder) {
		Preconditions.checkNotNull(thisBuilder, "ZkConfigBuilder should not be null");
		this.builder = thisBuilder;
		this.nodeFullPath = ZKPaths.makePath(ZkConfigConstant.CFG_PATH, builder.getConfigFullPath());
		init();
	}

	public void init() {
		try {
			this.cache = new PathChildrenCache(ZkClientHelper.getZkClient(), ZKPaths.makePath(builder.getPrefixFullPath(), builder.getConfigFullPath()),
					builder.getIfCacheData());//
			this.cache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE);
			if (builder.getZKConfigListener() != null) {
				addListener(builder.getZKConfigListener());
			}
		} catch (Exception e) {
			log.error("Init ZKConfig Error:", e);
			CloseableUtils.closeQuietly(this.cache);
			throw new RuntimeException(e);
		}
	}

	@Override
	public void close() {
		CloseableUtils.closeQuietly(this.cache);
		this.cache = null;

	}

	@Override
	public String getValue(String key) throws Exception {
		String path = ZKPaths.makePath(this.nodeFullPath, key);
		ChildData data = this.cache.getCurrentData(path);
		String rtnStr = null;
		if (data != null) {
			byte[] byteAry = data.getData();
			if (byteAry != null) {
				rtnStr = new String(byteAry, "UTF-8");
			} else {
				log.debug("ChildData.getData is null, path=[{}]", path);
			}
		} else {
			log.debug("ChildData is null, path=[{}]", path);
		}
		return rtnStr;
	}

	@Override
	public String getValue(String key, String defaultValue) throws Exception {

		String tmpRtn = this.getValue(key);
		if (tmpRtn == null) {
			return defaultValue;
		}
		return tmpRtn;
	}

	@Override
	public Map<String, String> listAll() throws Exception {
		Map<String, String> rtnMap = Maps.newHashMap();
		if (this.cache.getCurrentData().size() == 0) {
			log.debug("* empty *");
		} else {
			for (ChildData data : this.cache.getCurrentData()) {
				log.debug("Node listed: {}={}", data.getPath(), new String(data.getData(), "UTF-8"));

				rtnMap.put(ZKPaths.getNodeFromPath(data.getPath()), new String(data.getData(), "UTF-8"));
			}
		}
		return rtnMap;
	}

	private void addListener(PathChildrenCacheListener pathChildrenCacheListener) {
		this.cache.getListenable().addListener(pathChildrenCacheListener);

	}

}
